package functionTypes;

import java.util.Random;

import tasks.BoilerControlSystem;
import Abstracts.AbstractFunction;
import Abstracts.AbstractGeneticFunction;
import Abstracts.AbstractSinglePropertyFunction;

public class SamplingFunction implements AbstractGeneticFunction, Cloneable {

	public AbstractSinglePropertyFunction[] subfunctions;
	int samplesCount = 100;
	double leftBorder = 20;
	double rightBorder = 100;

	public SamplingFunction clone() throws CloneNotSupportedException {
		SamplingFunction obj = (SamplingFunction) super.clone();
		obj.subfunctions = new AbstractSinglePropertyFunction[subfunctions.length];
		for (int i = 0; i != subfunctions.length; ++i) {
			obj.subfunctions[i] = subfunctions[i].clone();
		}
		obj.samplesCount = samplesCount;
		obj.leftBorder = leftBorder;
		obj.rightBorder = rightBorder;
		return obj;
	}

	/*
	 * public void clone(AbstractFunction f){ f = new SamplingFunction();
	 * AbstractSinglePropertyFunction[] subs = new
	 * AbstractSinglePropertyFunction[this.subfunctions.length]; for (int
	 * i=0;i!=subs.length;++i){ subfunctions[i].clone(subs[i]); }
	 * f.createAbstractFunction(subs); ((SamplingFunction)f).samplesCount =
	 * this.samplesCount; ((SamplingFunction)f).leftBorder = this.leftBorder;
	 * ((SamplingFunction)f).rightBorder = this.rightBorder; }
	 */
	public void setBorders(double left, double right) throws Exception {
		if (left < right) {
			leftBorder = left;
			rightBorder = right;
		} else {
			throw new Exception("Left border shoud be lower than right");
		}
	}

	public SamplingFunction() {
		generateFunction();
	}

	public void bigMutate() {
		generateFunction();
	}

	public void mutate(double chance) {
		for (int i = 0; i != subfunctions.length; ++i) {
			if (Math.random() < chance)
				subfunctions[i].getCoeff()[0] = Math.random();
		}
	}

	public double compute(double[] params) {
		double step = (rightBorder - leftBorder) / samplesCount;
		int sampleIndex = (int) (Math.abs((params[0] - leftBorder) / step));
		if (sampleIndex == samplesCount)
			--sampleIndex;
		return subfunctions[sampleIndex].compute(params[0]);
	}

	public void createAbstractFunction(AbstractSinglePropertyFunction[] args) {
		subfunctions = args;
	}

	public void generateFunction() {
		subfunctions = new OldSinglePropertyFunction[samplesCount];
		for (int i = 0; i != subfunctions.length; ++i) {
			subfunctions[i] = new OldSinglePropertyFunction();
			if (subfunctions[i].getType() == 0) {
				subfunctions[i].getCoeff()[0] = Math.random();
			} else if (subfunctions[i].getType() == 1) {
				subfunctions[i].getCoeff()[0] = Math.random();
			} else if (subfunctions[i].getType() == 2) {
				subfunctions[i].getCoeff()[0] = Math.random() / Math.PI;
			} else if (subfunctions[i].getType() == 3) {
				subfunctions[i].setDefaultType();
			} else if (subfunctions[i].getType() == 4) {
				subfunctions[i].setDefaultType();
			} else if (subfunctions[i].getType() == 5) {
				subfunctions[i].setDefaultType();
			}
		}
	}

	public SamplingFunction[] crossover(SamplingFunction f) throws CloneNotSupportedException {
		SamplingFunction new1 = new SamplingFunction();
		SamplingFunction new2 = new SamplingFunction();

		int beginIndex1 = (int) (Math.random() * (samplesCount - 20));
		int beginIndex2 = (int) (Math.random() * (samplesCount - 20));
		int length = (int) (Math.random() * 15 + 5);
		int endIndex1 = beginIndex1 + length - 1;
		int endIndex2 = beginIndex2 + length - 1;

		for (int i = 0; i != subfunctions.length; ++i) {
			new1.subfunctions[i] = null;
			new2.subfunctions[i] = null;
		}

		int k = 0;

		for (int i = beginIndex1; i != endIndex1; ++i) {
			new1.subfunctions[i] = f.subfunctions[beginIndex2+k].clone();
			++k;
		}
		
		k = 0;

		for (int i = beginIndex2; i != endIndex2; ++i) {
			new2.subfunctions[i] = subfunctions[beginIndex1+k].clone();
			++k;
		}
		
		for (int i = 0; i != subfunctions.length; ++i) {
			if (new1.subfunctions[i] == null){
				new1.subfunctions[i] = subfunctions[i].clone();
			}
			if (new2.subfunctions[i] == null){
				new2.subfunctions[i] = f.subfunctions[i].clone();
			}
		}
		return new SamplingFunction[] { this, f, new1, new2 };
	}

	public AbstractSinglePropertyFunction[] getSubFunctions() {
		return subfunctions;
	}

}
